#include "SSB_flash_storage.h"
#include "nvs_flash.h"
#include "string.h"
#include "esp_wifi.h"
#include "SSB_sys_def.h"
#include "esp_log.h"

#ifdef PLATFORM_ESP32
#include <sys/unistd.h>
#include <ctype.h>
#include <sys/fcntl.h>
#include "esp_vfs.h"
#include <sys/stat.h>
#include "esp_spiffs.h"

#define SSB_SPIFFS_BASE_PATH "/ssb_fs"
#endif

#define SSB_NVS_DATA ("SSB_D")



void SSB_flash_nvs_storage(char *key, char *data, int len)
{
    nvs_handle handle;
    ESP_ERROR_CHECK(nvs_open(SSB_NVS_DATA, NVS_READWRITE, &handle));
    ESP_ERROR_CHECK(nvs_set_blob(handle, key, data, len));
    ESP_ERROR_CHECK(nvs_commit(handle));
    nvs_close(handle);
}

void SSB_read_data_from_nvs_flash(char *key, char *data, int maxLen)
{
    nvs_handle handle;
    int ret = nvs_open(SSB_NVS_DATA, NVS_READONLY, &handle);
    if (ret != ESP_OK)
    {
        nvs_close(handle);
        return;
    }
    nvs_get_blob(handle, key, data, (uint32_t *)&maxLen);
    nvs_close(handle);
}

#ifdef PLATFORM_ESP32
void SSB_flash_list_file(SSB_fs_list_file_cb cb)
{

    DIR *dir = NULL;
    struct dirent *ent;
    dir = opendir(SSB_SPIFFS_BASE_PATH);
    if (!dir)
    {
        ESP_LOGI(SSB_TAG, "[Flash]%s", "Error opening directory");
        return;
    }
    int i=0;
    while ((ent = readdir(dir)) != NULL)
    {
        i=i+1;
        //ESP_LOGI(SSB_TAG, "File name=%s", ent->d_name);
        int cb_rs=0;
        if(cb!=NULL){
            cb_rs=cb(ent,0,i);
        }
        if(cb_rs<0){
            break;
        }
    }
    
    closedir(dir);
    if(cb!=NULL){
        cb(NULL,1,i);
    }
    
}


int SSB_flash_fs_rename(char *src, char *desc)
{
    char src_file_path[64] = {0};
    sprintf(&src_file_path[0], "%s/%s", SSB_SPIFFS_BASE_PATH, src);
    struct stat st;
    if (stat(src_file_path, &st) != 0)
    {
        return -1;
    }
    char desc_file_path[64] = {0};
    sprintf(&desc_file_path[0], "%s/%s", SSB_SPIFFS_BASE_PATH, desc);
    if (stat(desc_file_path, &st) == 0)
    {
        unlink(desc_file_path);
    }
    if (rename(src_file_path, desc_file_path) != 0)
    {
        ESP_LOGE(SSB_TAG, "Rename failed");
        return -1;
    }
    return 0;
}

int SSB_flash_fs_storage(char *filename, char *data, int len, int mode)
{

    if (strstr(filename, "\n") != NULL)
    {
        ESP_LOGE(SSB_TAG, "Invalid file name");
        return -1;
    }

    char file_path[64] = {0};
    FILE *f = NULL;
    sprintf(&file_path[0], "%s/%s", SSB_SPIFFS_BASE_PATH, filename);
    if (mode == 1)
    {
        //覆盖
        f = fopen(file_path, "w");
    }
    else if (mode == 2)
    {
        //追加
        f = fopen(file_path, "ab");
    }
    if (f == NULL)
    {
        ESP_LOGE(SSB_TAG, "Failed to open file for writing");
        return -1;
    }
    fwrite(data, sizeof(char), len, f);
    fclose(f);
    return 0;

}

/*
*
max_byte 最大字节数
mode: 1 按行的方式读取，0按字节方式读取
*/
void SSB_flash_fs_cb_read(char *filename, int max_byte, int mode, SSB_fs_read_callback_fun cb)
{
    char file_path[64] = {0};
    sprintf(&file_path[0], "%s/%s", SSB_SPIFFS_BASE_PATH, filename);
    FILE *f = fopen(file_path, "r");
    if (f == NULL)
    {
        ESP_LOGE(SSB_TAG, "Failed to open file for reading");
        return;
    }
    char buf[max_byte];
    int is_break = 0;
    if (mode == 1)
    {
        while (fgets(buf, sizeof(buf), f) != NULL)
        {
            if (cb != NULL)
            {
                is_break = cb(buf, strlen(buf));
            }
            if (is_break < 0)
            {
                break;
            }
        }
    }
    else
    {
        int read_len = 0;
        while (1)
        {
            read_len = fread(buf, sizeof(char), max_byte, f);
            if (read_len < 1)
            {
                break;
            }
            if (cb != NULL)
            {
                is_break = cb(buf, read_len);
            }
            if (is_break < 0)
            {
                break;
            }
        }
    }
    if (cb != NULL)
    {
        is_break = cb(NULL, -1);
    }
    fclose(f);
}

int SSB_flash_fs_remove(char *filename)
{
    char file_path[64] = {0};
    sprintf(&file_path[0], "%s/%s", SSB_SPIFFS_BASE_PATH, filename);
    struct stat st;
    if (stat(file_path, &st) == 0)
    {

        unlink(file_path);
    }
    return 0;
}

void SSB_flash_fs_init()
{
    esp_vfs_spiffs_conf_t conf = {
        .base_path = SSB_SPIFFS_BASE_PATH,
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true};

    // Use settings defined above to initialize and mount SPIFFS filesystem.
    // Note: esp_vfs_spiffs_register is an all-in-one convenience function.
    esp_err_t ret = esp_vfs_spiffs_register(&conf);

    if (ret != ESP_OK)
    {
        if (ret == ESP_FAIL)
        {
            ESP_LOGE(SSB_TAG, "Failed to mount or format filesystem");
        }
        else if (ret == ESP_ERR_NOT_FOUND)
        {
            ESP_LOGE(SSB_TAG, "Failed to find SPIFFS partition");
        }
        else
        {
            ESP_LOGE(SSB_TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
        }
        return;
    }

    size_t total = 0, used = 0;
    ret = esp_spiffs_info(NULL, &total, &used);
    if (ret != ESP_OK)
    {
        ESP_LOGE(SSB_TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
    }
    else
    {
        ESP_LOGI(SSB_TAG, "Partition size: total: %d, used: %d", total, used);
    }


}
#endif